package com.example.common.exception;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 全局异常处理器
 */
@ControllerAdvice
@Component("ExceptionHandler")
public class MyExceptionHandler {

    private final Logger logger = LoggerFactory.getLogger("MyExceptionHandler");
    private static final String ERROR_500 = "error/500";
    private static final String ERROR_404 = "error/404";
    private static final String ERROR_403 = "error/403";
    private static final String ERROR_VIEW = "error/global_error";

    @ExceptionHandler(Exception.class)
//    @ResponseBody
//    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public Object errorHandler(HttpServletRequest request, Exception ex) {
        Map<String, Object> map = new HashMap<>();
        ModelAndView mv = new ModelAndView();
        ex.printStackTrace();//打印异常信息
        // 根据不同错误获取错误信息
        if (ex instanceof BusinessException) {
            map.put("code", ((IException) ex).getCode());
            map.put("msg", ex.getMessage());
            map.put("data", ex);
        } else if (ex instanceof NullPointerException) {
            map.put("code", 500);
            map.put("msg", "空指针异常");
            map.put("data", ex.getMessage());
        }else if (ex instanceof ClassCastException) {
            map.put("code", 500);
            map.put("msg", "类型转换异常");
            map.put("data", ex.getMessage());
        }else if (ex instanceof NoSuchMethodException) {
            map.put("code", 500);
            map.put("msg", "未知方法异常");
            map.put("data", ex.getMessage());
        }else if (ex instanceof IOException) {
            map.put("code", 500);
            map.put("msg", "IO异常");
            map.put("data", ex.getMessage());
        }else if (ex instanceof IndexOutOfBoundsException) {
            map.put("code", 500);
            map.put("msg", "数组越界异常");
            map.put("data", ex.getMessage());
        } else {
            String message = ex.getMessage();
            map.put("code", 500);
            //map.put("msg", "系统繁忙");
            // 开发阶段建议错误信息直接放在msg中，生产版本建议把错误信息放在data中，msg提示系统繁忙即可
            map.put("msg", message == null || message.trim().isEmpty() ? "未知异常，请联系管理员" : message);
            map.put("data", message);
            logger.error(ex.getMessage(), ex);
        }
        if(isAjax(request)){
            return map;
        }else {
            Integer code= (Integer) map.get("code");
            mv.addObject("code", code);
            mv.addObject("msg", map.get("msg"));
            mv.addObject("exMessage", ex.getMessage());
            mv.addObject("stackTrace", ex.getStackTrace());
            mv.addObject("url", request.getRequestURL());//发生异常的路径
            if (code==500){
                mv.setViewName(ERROR_500);//指定发生异常之后跳转页面
            }else if (code==404){
                mv.setViewName(ERROR_404);
            }else if (code==403){
                mv.setViewName(ERROR_403);
            }else{
                mv.setViewName(ERROR_VIEW);
            }
            return mv;
        }
    }

    /**
     * 判断是不是ajax请求
     */
    private boolean isAjax(HttpServletRequest request) {
        String xHeader = request.getHeader("X-Requested-With");
        return xHeader != null && xHeader.contains("XMLHttpRequest");
    }
}
